package no.uib.hplims.views.peptides;

import java.util.List;

import org.vaadin.appfoundation.persistence.facade.FacadeFactory;

import com.vaadin.data.Container;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.DefaultFieldFactory;
import com.vaadin.ui.Field;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.NativeSelect;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.Runo;

import no.uib.hplims.models.Peptide;
import no.uib.hplims.models.peptideinformation.Ion;
import no.uib.hplims.models.peptideinformation.PeptideInformation;
import no.uib.hplims.models.peptideinformation.Transition;
import no.uib.hplims.tools.events.UpdatePeptideInformationEvent;
import no.uib.hplims.tools.events.UpdatePeptideInformationListener;

public class TransitionView extends AbstractInformationView<Transition> {

	private static final long serialVersionUID = 601317678710311671L;

	private VerticalLayout optimizationLayout = null;

	// Create the listener list
	protected javax.swing.event.EventListenerList listenerList = new javax.swing.event.EventListenerList();
	
	private Peptide peptide;
	
	private TextField machineField;
	private TextField initialsField;

	protected TransitionView(List<Transition> transitions,
			PeptideInformation pi, Peptide p) {
		super(Transition.class, pi);
		peptide = p;

		setCaption("Optimization");

		addOptimizationInformation();

		init(transitions);

		addVisibleColumns();
	}

	private void addOptimizationInformation() {
		optimizationLayout = new VerticalLayout();
		optimizationLayout.setSpacing(true);

		HorizontalLayout hl = new HorizontalLayout();
		hl.setSpacing(true);
		
		VerticalLayout checkBoxLayout = new VerticalLayout();
		checkBoxLayout.setMargin(false, true, false, false);
		checkBoxLayout.addComponent(new Label("Optimized: "));
		CheckBox checkBox = new CheckBox("",
				peptideInformation.isOptimized());
		checkBox.setImmediate(true);
		checkBox.addListener(checkBoxValueChangeListener);
		checkBoxLayout.addComponent(checkBox);
		checkBoxLayout.setComponentAlignment(checkBox, Alignment.MIDDLE_CENTER);
		hl.addComponent(checkBoxLayout);

		//hl.addComponent(new Label("Machine: "));
		machineField = new TextField("Machine: ");
		machineField.setValue(peptideInformation.getMachine());
		machineField.setImmediate(true);
		machineField.setColumns(20);
		machineField.addListener(machineFieldListener);
		hl.addComponent(machineField);
		
		//hl.addComponent(new Label("Optimized by: "));
		initialsField = new TextField("Optimized by: ");
		initialsField.setValue(peptideInformation.getInitials());
		initialsField.addListener(initialsFieldListener);
		initialsField.setImmediate(true);
		initialsField.setColumns(20);
		hl.addComponent(initialsField);
		
		if (!peptideInformation.isOptimized()) {
			machineField.setEnabled(false);
			initialsField.setEnabled(false);
		}

		optimizationLayout.addComponent(hl);

		addComponent(optimizationLayout);

		Label l = new Label("Transitions:");
		l.setStyleName(Runo.LABEL_SMALL);
		addComponent(l);
	}

	@Override
	protected void addVisibleColumns() {

		visibleColumnIds.add("q1");
		visibleColumnIds.add("q3");
		visibleColumnIds.add("ion");
		visibleColumnIds.add("fragmentIon");
		visibleColumnIds.add("declusteringPotential");
		visibleColumnIds.add("exitPotential");
		visibleColumnIds.add("collissionEnergy");
		visibleColumnIds.add("collissionExitPotential");
		visibleColumnIds.add("mass");
		visibleColumnIds.add("working");
		visibleColumnIds.add("rank");

		visibleColumnLabels.add("Q1");
		visibleColumnLabels.add("Q3");
		visibleColumnLabels.add("Ion");
		visibleColumnLabels.add("Fragment ion");
		visibleColumnLabels.add("DP");
		visibleColumnLabels.add("EP");
		visibleColumnLabels.add("CE");
		visibleColumnLabels.add("CXP");
		visibleColumnLabels.add("Mass");
		visibleColumnLabels.add("Working?");
		visibleColumnLabels.add("Rank");

		itemTable.setVisibleColumns(visibleColumnIds.toArray());
		itemTable.setColumnHeaders(visibleColumnLabels.toArray(new String[0]));
	}

	public void buttonClick(ClickEvent event) {
		if (event.getButton().equals(editButton)) {

			editMode = !editMode;
			editButtonClick(editMode);

		} else if (event.getButton().equals(newButton)) {

			Transition t = new Transition();
			FacadeFactory.getFacade().store(t);
			itemContainer.addBean(t);
			editMode = true;
			editButtonClick(editMode);

		}
	}

	private void editButtonClick(boolean edit) {
		itemTable.setEditable(edit);
		itemTable.setTableFieldFactory(getFieldFactory());

		if (edit) {
			editButton.setCaption("Save");
		} else {
			editButton.setCaption("Edit");

			for (Transition t : itemContainer.getItemIds()) {
				peptideInformation.addTransition(t);
				FacadeFactory.getFacade().store(t);
			}
			FacadeFactory.getFacade().store(peptideInformation);
		}
	}

	@Override
	protected DefaultFieldFactory getFieldFactory() {
		if (itemTableFieldFactory == null) {
			itemTableFieldFactory = new DefaultFieldFactory() {

				private static final long serialVersionUID = -6483548250027205519L;

				@Override
				public Field createField(Container container, Object itemId,
						Object propertyId, Component uiContext) {

					// Create fields by their class
					Class<?> cls = container.getType(propertyId);

					if (cls.equals(Ion.class)) {
						NativeSelect ns = new NativeSelect();
						ns.setNullSelectionAllowed(false);
						ns.setImmediate(true);
						ns.setSizeFull();

						for (Ion ion : Ion.values()) {
							ns.addItem(ion);
						}

						Transition t = (Transition) itemId;
						ns.setValue(t.getIon());

						return ns;
					}

					// Otherwise use the default field factory
					return super.createField(container, itemId, propertyId,
							uiContext);
				}
			};
		}

		return itemTableFieldFactory;
	}

	private ValueChangeListener checkBoxValueChangeListener = new ValueChangeListener() {
		private static final long serialVersionUID = -5390982311372994821L;

		public void valueChange(ValueChangeEvent event) {

			boolean active = (Boolean) event.getProperty().getValue();
			peptideInformation.setOptimized(active);
			FacadeFactory.getFacade().store(peptideInformation);
			
			machineField.setEnabled(active);
			initialsField.setEnabled(active);
			fireUpdatePeptideInformationEvent(new UpdatePeptideInformationEvent(this, peptide));

		}
	};
	
	private ValueChangeListener machineFieldListener = new ValueChangeListener() {
		private static final long serialVersionUID = -8489401367579035759L;

		public void valueChange(ValueChangeEvent event) {
			peptideInformation.setMachine((String) machineField.getValue());
			FacadeFactory.getFacade().store(peptideInformation);
			getWindow().showNotification("Saved");
		}
	};
	
	private ValueChangeListener initialsFieldListener = new ValueChangeListener() {
		private static final long serialVersionUID = 2789672396977379572L;

		public void valueChange(ValueChangeEvent event) {
			peptideInformation.setInitials((String) initialsField.getValue());
			FacadeFactory.getFacade().store(peptideInformation);
			getWindow().showNotification("Saved");
		}
	};

	// This methods allows classes to register for UpdatePeptideInformationEvents
	public void addListener(UpdatePeptideInformationListener listener) {
		listenerList.add(UpdatePeptideInformationListener.class, listener);
	}

	// This methods allows classes to unregister for UpdatePeptideInformationEvents
	public void removeListener(UpdatePeptideInformationListener listener) {
		listenerList.remove(UpdatePeptideInformationListener.class, listener);
	}

	// This private class is used to fire UpdatePeptideInformationEvents
	void fireUpdatePeptideInformationEvent(UpdatePeptideInformationEvent evt) {
		Object[] listeners = listenerList.getListenerList();
		// Each listener occupies two elements - the first is the listener class
		// and the second is the listener instance
		for (int i = 0; i < listeners.length; i += 2) {
			if (listeners[i] == UpdatePeptideInformationListener.class) {
				((UpdatePeptideInformationListener) listeners[i + 1])
						.eventOccurred(evt);
			}
		}
	}

}
